/**
  ******************************************************************************
  * @file    mb85rs64.c
  * @brief   This file provides code for the configuration
  *          of the SPI instances.
  ******************************************************************************
  * @attention
  *
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "bsp.h"
#include "mb85rs64.h"

#define mb85rs64_send_byte(x)     mb85rs64_spi_transbyte(x, NULL)
#define mb85rs64_read_byte(x)     mb85rs64_spi_transbyte(0, x)

static void mb85rs64_bsp_init(void)
{
  LL_SPI_InitTypeDef SPI_InitStruct = {0};
  LL_GPIO_InitTypeDef GPIO_InitStruct = {0};

  /* Peripheral clock enable */
  LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SPI1);
  LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOA);
  
  GPIO_InitStruct.Pin = FRAM_CS_LL_Pin;
  GPIO_InitStruct.Mode = LL_GPIO_MODE_OUTPUT;
  GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_HIGH;
  GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
  GPIO_InitStruct.Pull = LL_GPIO_PULL_UP;
  LL_GPIO_Init(FRAM_CS_GPIO_Port, &GPIO_InitStruct);
  
  /**SPI1 GPIO Configuration
  PA5   ------> SPI1_SCK
  PA6   ------> SPI1_MISO
  PA7   ------> SPI1_MOSI
  */
  GPIO_InitStruct.Pin = FRAM_SCK_Pin|FRAM_MISO_Pin|FRAM_MOSI_Pin;
  GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
  GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;
  GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
  GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
  GPIO_InitStruct.Alternate = LL_GPIO_AF_5;
  LL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  SPI_InitStruct.TransferDirection = LL_SPI_FULL_DUPLEX;
  SPI_InitStruct.Mode = LL_SPI_MODE_MASTER;
  SPI_InitStruct.DataWidth = LL_SPI_DATAWIDTH_8BIT;
  SPI_InitStruct.ClockPolarity = LL_SPI_POLARITY_HIGH;
  SPI_InitStruct.ClockPhase = LL_SPI_PHASE_2EDGE;
  SPI_InitStruct.NSS = LL_SPI_NSS_SOFT;
  SPI_InitStruct.BaudRate = LL_SPI_BAUDRATEPRESCALER_DIV2;
  SPI_InitStruct.BitOrder = LL_SPI_MSB_FIRST;
  SPI_InitStruct.CRCCalculation = LL_SPI_CRCCALCULATION_DISABLE;
  SPI_InitStruct.CRCPoly = 10;
  LL_SPI_Init(FRAM_SPI, &SPI_InitStruct);
  
  LL_SPI_Enable(FRAM_SPI);
}

static inline int32_t mb85rs64_spi_transbyte(uint8_t txdat, uint8_t *rxdat)
{
  __IO uint8_t rx;
  
  while(READ_BIT(FRAM_SPI->SR, SPI_SR_TXE) == RESET)
  {
    /* TODO: timeout deal */
  }

   __IO uint8_t *spidr = ((__IO uint8_t *)&FRAM_SPI->DR);
  *spidr = txdat;


  while(READ_BIT(FRAM_SPI->SR, SPI_SR_RXNE) == RESET)
  {
    /* TODO: timeout deal */
  }

  rx = (*((__IO uint8_t *)&FRAM_SPI->DR));
  
  if(rxdat != NULL)
  {
    *rxdat = rx;
  }
  
  return 0;
}

/**
  * @brief  读取mb85rs64的状态寄存器
  * @param  无
  * @retval 状态寄存器值
  */
uint8_t mb85rs64_read_status_reg(void)
{
  uint8_t rcv = 0;   /* 初始化,防止读取失败后出现随机值 */

  mb85rs64_select();

  mb85rs64_send_byte(MB85RS64_OPCODE_RDSR);
  mb85rs64_read_byte(&rcv);

  mb85rs64_deselect();

  return rcv;
}

/**
  * @brief  写mb85rs64的状态寄存器
  * @param  u8Val: 要写入的值
  * @retval 无
  */
void mb85rs64_write_status_reg(uint8_t value)
{
  mb85rs64_select();

  mb85rs64_send_byte(MB85RS64_OPCODE_WRSR);
  mb85rs64_send_byte(value);

  mb85rs64_deselect();
}

/**
  * @brief  设置mb85rs64的块保护范围
  * @param  BPsize: 设置写入保护的范围.可以是以下值之一：
    @arg    mb85rs64_BP_NON     : 无保护
    @arg    mb85rs64_BP_QUARTER : 保护高1/4，0x1800 - 0x1FFF
    @arg    mb85rs64_BP_HALF    : 保护高1/2，0x1000 - 0x1FFF
    @arg    mb85rs64_BP_ALL     : 保护全部， 0x0000 - 0x1FFF
  * @retval 无
  */
void mb85rs64_set_bp(MB85RS64_BpEnum bpsize)
{
  mb85rs64_select();

  mb85rs64_send_byte(MB85RS64_OPCODE_WREN);

  mb85rs64_deselect();
  mb85rs64_deselect();

  mb85rs64_write_status_reg(bpsize);
}

/**
  * @brief  从MB85RS64的FRAM读取1字节数据
  * @param  u16Address: 数据所在地址
  * @retval 读出的值
  */
uint8_t mb85rs64_read_one_byte(uint16_t address)
{
  uint8_t rcv = 0;  /* 初始化,防止读取失败后出现随机值 */

  mb85rs64_select();

  mb85rs64_send_byte(MB85RS64_OPCODE_READ);
  mb85rs64_send_byte((uint8_t)(address >> 8));
  mb85rs64_send_byte((uint8_t)address);
  mb85rs64_read_byte(&rcv);

  mb85rs64_deselect();

  return rcv;
}

/**
  * @brief  从MB85RS64的FRAM读取2字节数据
  * @param  u16Address: 数据所在地址
  * @retval 读出的值
  */
uint16_t mb85rs64_read_two_byte(uint16_t address)
{
  uint8_t rcvl = 0;  /* 初始化,防止读取失败后出现随机值 */
  uint8_t rcvh = 0;
  uint16_t rcv = 0;
  
  mb85rs64_select();
  
  mb85rs64_send_byte(MB85RS64_OPCODE_READ);
  mb85rs64_send_byte((uint8_t)(address >> 8));
  mb85rs64_send_byte((uint8_t)address);
  
  mb85rs64_read_byte(&rcvh);
  mb85rs64_read_byte(&rcvl);
  
  mb85rs64_deselect();
  
  rcv = ((((uint16_t)rcvh) << 8) & 0xFF00u) + rcvl;
  
  return rcv;
}

/**
  * @brief  从MB85RS64的FRAM读取4字节数据
  * @param  u16Address: 数据所在地址
  * @retval 读出的值
  */
uint32_t mb85rs64_read_four_byte(uint16_t address)
{
  uint8_t rcv1 = 0;
  uint8_t rcv2 = 0;
  uint8_t rcv3 = 0;
  uint8_t rcv4 = 0;
  uint32_t rcv = 0;
  
  mb85rs64_select();
  
  mb85rs64_send_byte(MB85RS64_OPCODE_READ);
  mb85rs64_send_byte((uint8_t)(address >> 8));
  mb85rs64_send_byte((uint8_t)address);
  
  mb85rs64_read_byte(&rcv1);
  mb85rs64_read_byte(&rcv2);
  mb85rs64_read_byte(&rcv3);
  mb85rs64_read_byte(&rcv4);
  
  mb85rs64_deselect();
  
  rcv = ((((uint32_t)rcv1) << 24) & 0xFF000000u) + \
        ((((uint32_t)rcv2) << 16) & 0x00FF0000u) + \
        ((((uint32_t)rcv3) << 8)  & 0x0000FF00u) + rcv4;

  return rcv;
}

/**
  * @brief  从MB85RS64的FRAM读取任意字节数量的数据
  * @param  address: 数据所在地址
  * @param  rdat: 待写入数据指针
  * @param  len:  待写入数据长度
  * @retval 读出的值
  */
uint8_t mb85rs64_read_bytes(uint16_t address, uint8_t *rdat, uint16_t len)
{
  uint16_t i;
  
  mb85rs64_select();
  
  mb85rs64_send_byte(MB85RS64_OPCODE_READ);
  mb85rs64_send_byte((uint8_t)(address >> 8));
  mb85rs64_send_byte((uint8_t)address);
  
  for(i=0; i<len; i++)
  {
    mb85rs64_read_byte(&rdat[i]);
  }
  
  mb85rs64_deselect();
  
  return 0;
}

/**
  * @brief  向MB85RS64的FRAM写入1字节数据
  * @param  u16Address: 数据所在地址
  * @param  u8Data: 数据
  * @retval 无
  */
void mb85rs64_write_one_byte(uint16_t address, uint8_t wdat)
{
  mb85rs64_select();
  
  mb85rs64_send_byte(MB85RS64_OPCODE_WREN);
  
  mb85rs64_deselect();
  mb85rs64_deselect();
  
  
  mb85rs64_select();
  
  mb85rs64_send_byte(MB85RS64_OPCODE_WRITE);
  mb85rs64_send_byte((uint8_t)(address >> 8));
  mb85rs64_send_byte((uint8_t)address);
  
  mb85rs64_send_byte(wdat);
  
  mb85rs64_deselect();
}

/**
  * @brief  向MB85RS64的FRAM写入2字节数据
  * @param  u16Address: 数据所在地址
  * @param  u16Data: 数据
  * @retval 无
  */
void mb85rs64_write_two_byte(uint16_t address, uint16_t wdat)
{
  mb85rs64_select();
  
  mb85rs64_send_byte(MB85RS64_OPCODE_WREN);
  
  mb85rs64_deselect();
  mb85rs64_deselect();
  
  
  mb85rs64_select();
  
  mb85rs64_send_byte(MB85RS64_OPCODE_WRITE);
  mb85rs64_send_byte((uint8_t)(address >> 8));
  mb85rs64_send_byte((uint8_t)address);
  
  mb85rs64_send_byte((uint8_t)(wdat >> 8));
  mb85rs64_send_byte((uint8_t)wdat);
  
  mb85rs64_deselect();
}

/**
  * @brief  向MB85RS64的FRAM写入4字节数据
  * @param  u16Address: 数据所在地址
  * @param  u32Data: 数据
  * @retval 无
  */
void mb85rs64_write_four_byte(uint16_t address, uint32_t wdat)
{
  mb85rs64_select();
  
  mb85rs64_send_byte(MB85RS64_OPCODE_WREN);
  
  mb85rs64_deselect();
  mb85rs64_deselect();
  
  
  mb85rs64_select();
  
  mb85rs64_send_byte(MB85RS64_OPCODE_WRITE);
  mb85rs64_send_byte((uint8_t)(address >> 8));
  mb85rs64_send_byte((uint8_t)address);
  
  mb85rs64_send_byte((uint8_t)(wdat >> 24));
  mb85rs64_send_byte((uint8_t)(wdat >> 16));
  mb85rs64_send_byte((uint8_t)(wdat >> 8));
  mb85rs64_send_byte((uint8_t)wdat);
  
  mb85rs64_deselect();
}

/**
  * @brief  向MB85RS64的FRAM写入任意字节数据
  * @param  address: 数据所在地址
  * @param  wdat: 写入数据
  * @param  len:  数据长度
  * @retval 无
  */
uint8_t mb85rs64_write_bytes(uint16_t address, const uint8_t *wdat, uint16_t len)
{
  uint16_t i;
  
  mb85rs64_select();
  
  mb85rs64_send_byte(MB85RS64_OPCODE_WREN);
  
  mb85rs64_deselect();
  mb85rs64_deselect();
  
  
  mb85rs64_select();
  
  mb85rs64_send_byte(MB85RS64_OPCODE_WRITE);
  mb85rs64_send_byte((uint8_t)(address >> 8));
  mb85rs64_send_byte((uint8_t)address);
  
  for(i=0; i<len; i++)
  {
    mb85rs64_send_byte(wdat[i]);
  }
  
  mb85rs64_deselect();
  
  return 0;
}

/**
 * @brief  初始化MB85RS64
 * @param  无
 * @retval 无
 */
void mb85rs64_init(void)
{
  mb85rs64_bsp_init();
  
  mb85rs64_set_bp(MB85RS64_BP_NON);
}
